/*******************************************************************************
 * Copyright 2010 Prometheus Consulting
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package nz.co.senanque.maduradocs.translation;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.ProcessingInstruction;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * 
 * This tidies up the generated file from Word and also locates the EMF inage files
 * and translates them to PNG. We use the freehep package for the translation
 * 
 * @author Roger Parkinson
 *
 */
public class Translator {

	private static Map<String,String> imageMap = new HashMap<String,String>();
	private static Set<String> headings = new HashSet<String>();
	/**
	 * @param args
	 */
	public static void main(String[] args) {
	    
	    for (String s: args)
	    {
	        System.out.println(s);
	    }
	    //printClasspath();
		
        String fileName = args[0];
        String workingDir = args[1];
        String docDir = args[2];
		System.out.println("working.dir="+args[1]);
		String outFile = docDir+"/"+args[0]+".xml";
		System.out.println("outfile="+outFile);
		
		SAXBuilder builder = new SAXBuilder();
		Document doc = null;
		Document doc1 = null;
		
	    try {
	        doc = builder.build(workingDir+"/"+fileName+"/int.xml");
	        doc1 = builder.build(workingDir+"/"+fileName+"/document.xml.rels");
	      }
	      // indicates a well-formedness error
	      catch (JDOMException e) { 
	        System.out.println(args[0] + " is not well-formed.");
	        System.out.println(e.getMessage());
	        System.exit(1);
	      }  
	      catch (IOException e) { 
	        System.out.println("Could not check " + args[0]);
	        System.out.println(" because " + e.getMessage());
	        System.exit(1);
	      }
	      Document newDocument = new Document();
	      ProcessingInstruction pi = new ProcessingInstruction("xml-stylesheet",
	      "type='text/xsl' href='MaduraHTML.xsl'");
	      newDocument.addContent(pi);
	      Element root = new Element("doc");
  	      root.addNamespaceDeclaration(Namespace.getNamespace("xsi","http://www.w3.org/2001/XMLSchema-instance"));
	      root.addNamespaceDeclaration(Namespace.getNamespace("xi","http://www.w3.org/2001/XInclude"));
	      root.addNamespaceDeclaration(Namespace.getNamespace("noNamespaceSchemaLocation","MaduraDoc.xsd"));
	      Element newBody = new Element("body");
	      newDocument.addContent(root);

	      Element title = doc.getRootElement().getChild("title");
	      String imagesDir = title.getChild("MainTitle").getText();
	      unpackRels(doc1,imageMap,imagesDir);
	      root.addContent(title.detach());
	      root.addContent(newBody);
	      
	      Element body = doc.getRootElement().getChild("body");
	      Stack<Element> stack = new Stack<Element>();
	      stack.push(newBody);
	      processElements(body,stack);
	      try 
	      {
			XMLOutputter outputter = new XMLOutputter();
			outputter.setFormat(Format.getPrettyFormat());
			PrintStream out = new PrintStream(new FileOutputStream(outFile));
			outputter.output(newDocument, out);
			out.close();
	      } 
	      catch (IOException e) 
	      {
			e.printStackTrace();
			System.exit(1);
	      }
	      File f = new File(docDir+"/"+fileName);
	      f.mkdir();
	      translateEMF(workingDir+"/"+fileName, docDir+"/"+fileName);
	      
	}
	private static void printClasspath()
	{
        ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();

        //Get the URLs
        URL[] urls = ((URLClassLoader)sysClassLoader).getURLs();

        for(int i=0; i< urls.length; i++)
        {
            System.out.println(urls[i].getFile());
        }       

	}
	private static void translateEMF(String imagedir, String targetDir)
	{
		File imagesFile = new File(imagedir);
		String[] images = imagesFile.list(new FilenameFilter(){

			public boolean accept(File arg0, String arg1) {
				if (arg1.endsWith(".emf")) return true;
				return false;
			}});
		for (String image: images)
		{
			String emfFile = imagedir+"/"+image;
			int i = image.lastIndexOf('.');
			String pngFile = targetDir+"/"+image.substring(0,i)+".png";
	         System.out.println("Translating: "+emfFile+" to "+pngFile);
//			org.freehep.graphicsio.emf.EMFConverter.export("PNG",emfFile,null);
			EMFConverter.main(new String[]{emfFile,pngFile});
		}
	}
	private static void unpackRels(Document doc1, Map<String, String> imageMap2, String imagesDir) {
		List<Element> children = doc1.getRootElement().getChildren();
		for (Element e: children)
		{
			String id = e.getAttributeValue("Id");
			String target = e.getAttributeValue("Target");
			int i = target.indexOf("/");
			if (i == -1)
			{
				imageMap2.put(id, target);
				continue;
			}
			imageMap2.put(id, imagesDir+target.substring(i));
		}		
	}
	private static void processElements(Element parent, Stack<Element> stack)
	{
	    
		Element lastImage = null;
		List<Element> children = parent.getChildren();
	     for (Element child: children)
	     {
	    	 try {
				String stackParentName = stack.lastElement().getName();
				 if (child.getAttribute("list") != null)
				 {
					 // we found a list
					 if (!stackParentName.equals("list"))
					 {
						 Element list = new Element("list");
						 stack.lastElement().addContent(list);
						 stack.push(list);
					 }
					 Element le = new Element("le");
					 le.setText(child.getText());
					 stack.lastElement().addContent(le);
					 continue;
				 }
				 else
				 {
					 if (stackParentName.equals("list"))
						 stack.pop();
				 }
				 if (child.getName().equals("code"))
				 {
					 // we found a code tag
					 if (!stackParentName.equals("code"))
					 {
						 Element code = new Element("code");
						 stack.lastElement().addContent(code);
						 stack.push(code);
					 }
					 Element code = stack.lastElement();
					 code.setText(code.getText()+"\n"+child.getText());
					 continue;
				 }
				 else
				 {
					 if (stackParentName.equals("code"))
						 stack.pop();
				 }
				 if (child.getName().startsWith("h"))
				 {
					 while (stackParentName.startsWith("h") && child.getName().compareTo(stackParentName) <= 0)
					 {
						 stack.pop();
						 stackParentName = stack.lastElement().getName();
					 }
					 Element heading = new Element(child.getName());
					 String headingName = makeUnique(child.getText());
					 heading.setAttribute("t", headingName);
					 stack.lastElement().addContent(heading);
					 stack.push(heading);
					 continue;
				 }
				 if (child.getName().equals("img"))
				 {
					 String rid = child.getAttributeValue("rid");
					 String href = imageMap .get(rid);
					 if (href == null)
					 {
						 href = "NoImageFound";
					 }
					 if (href.endsWith(".emf"))
					 {
						 int i = href.lastIndexOf(".emf");
						 href = href.substring(0,i)+".png";
					 }
					 
					 Element img = new Element("img");
					 img.setAttribute("href", href);
					 img.setAttribute("width", "16cm");
					 img.setText(href);
					 stack.lastElement().addContent(img);
					 lastImage = img;
					 continue;
				 }
                 if (child.getName().equals("caption") && lastImage != null)
                 {
                     lastImage.setText(child.getTextTrim());
                     lastImage = null;
                     continue;
                 }
                 if (child.getName().equals("p"))
                 {
//                     List<Element> elements = child.getChildren();
//
//                     if (elements.size()==0 && (text == null || text.length()==0))
//                     {
//                         // Empty paragraph so don't keep it.
//                         continue;
//                     }
//                     if (elements.size()==1 && elements.get(0).getName().equals("p"))
//                     {
//                         // contains just one <p>
//                         text = elements.get(0).getTextTrim();
//                     }
//                     if (text != null && text.length()>0)
//                     {
//                         // If we have text assume that is all we need
//                         Element p = new Element("p");
//                         p.setText(text);
//                         stack.lastElement().addContent(p);
//                         continue;
//                     }
//                     if (elements.size()==1 && (text == null || text.length()==0))
//                     {
//                         // Empty paragraph so don't keep it.
//                         continue;
//                     }
                     String text = getText(child);
                     if (text.length()>0)
                     {
                         Element p = new Element("p");
                         p.setText(text);
                         stack.lastElement().addContent(p);
                         continue;
                     }
                     Element p = new Element("p");
                     stack.lastElement().addContent(p);
                     stack.push(p);
                     processElements(child,stack);
                     stack.pop();
                     continue;
                 }
                 if (child.getName().equals("table"))
                 {
                     Element newTable = new Element("table");
                     stack.lastElement().addContent(newTable);
                     stack.push(newTable);
                     processElements(child,stack);
                     stack.pop();
                     continue;
                 }
                 if (child.getName().equals("tr"))
                 {
                     Element e = new Element("tr");
                     stack.lastElement().addContent(e);
                     stack.push(e);
                     processElements(child,stack);
                     stack.pop();
                     continue;
                 }
                 if (child.getName().equals("td"))
                 {
                     String text = getText(child);
                     if (text.length()>0)
                     {
                         Element p = new Element("td");
                         p.setText(text);
                         stack.lastElement().addContent(p);
                         continue;
                     }
                     Element p = new Element("td");
                     stack.lastElement().addContent(p);
                     stack.push(p);
                     processElements(child,stack);
                     stack.pop();
                     continue;
//                     List<Element> pElements = child.getChildren("p");
//                     if (pElements.size()==1)
//                     {
//                         Element pElement = pElements.get(0);
//                         String text = pElement.getTextTrim();
//                         Element e = new Element("td");
//                         e.setText(text);
//                         stack.lastElement().addContent(e);
//                         continue;
//                     }
//                     if (pElements.size()>0)
//                     {
//                         Element e = new Element("td");
//                         stack.lastElement().addContent(e);
//                         stack.push(e);
//                         processElements(child,stack);
//                         stack.pop();
//                         continue;
//                     }
//                     if (child.getChildren("list").size()>0)
//                     {
//                         Element e = new Element("td");
//                         stack.lastElement().addContent(e);
//                         stack.push(e);
//                         processElements(child,stack);
//                         stack.pop();
//                         continue;
//                     }
                 }
				 stack.lastElement().addContent((Element)child.clone());
			} catch (Exception e) {
				XMLOutputter outputter = new XMLOutputter();
				outputter.setFormat(Format.getPrettyFormat());
				String element = outputter.outputString(child);
				throw new RuntimeException("Failed to process: "+element,e);
			}
	     }
	}
	private static String getText(Element e)
	{
	    String text = e.getTextTrim();
	    if (text != null && text.length()>0)
	    {
	        return text;
	    }
        List<Element> pElements = e.getChildren("p");
        if (pElements.size()==1)
        {
            return getText(pElements.get(0));
        }
	    return "";
	}
	private static String makeUnique(String headingName)
	{
	    while (headings.contains(headingName))
	    {
	        headingName+="_";
	    }
	    headings.add(headingName);
	    return headingName;
	}
}
